#include "DirectoryWatcher.h"

DirectoryWatcher::DirectoryWatcher(const QString &directory, QObject *parent)
    : QObject(parent)
    , m_directory(directory)
{
    // 监视新增和删除
    connect(&m_watcher, &QFileSystemWatcher::directoryChanged, this, &DirectoryWatcher::onDirectoryChanged);
    // 监视文件修改
    connect(&m_watcher, &QFileSystemWatcher::fileChanged, this, &DirectoryWatcher::onFileModify);

    // 添加监视的目录
    m_watcher.addPath(m_directory);

    // 初始化已知文件列表 并将现有文件添加至监视器
    updatePrevFiles();
}

void DirectoryWatcher::updatePrevFiles()
{
    m_prevFiles = QDir(m_directory).entryList(QDir::Files | QDir::NoDotAndDotDot);
    m_fName_MTime.clear();

    for (const QString &file : m_prevFiles)
    {
        //QString filePath = m_directory + "/" + file;
        QString filePath = QDir(m_directory).filePath(file);
        m_fName_MTime[file] = QFileInfo(filePath).lastModified();

        // 将现有文件添加至监视器
        m_watcher.addPath(filePath);
    }
}

void DirectoryWatcher::onDirectoryChanged(const QString &path)
{
    //qDebug() << "Directory changed:" << path;
    (void)path;
    // 获取当前文件列表
    QStringList curFiles = QDir(m_directory).entryList(QDir::Files | QDir::NoDotAndDotDot);
    QSet<QString> curFileSet(curFiles.begin(), curFiles.end());

    // 检查新增的文件
    for (const QString &curFile : curFileSet)
    {
        if (!m_prevFiles.contains(curFile))
        {
            //QString filePath = m_directory + "/" + curFile;
            QString filePath = QDir(m_directory).filePath(curFile);
            emit fileAdded(filePath);
            qDebug() << "File added:" << filePath;

            m_prevFiles.append(curFile);
            QFileInfo fileInfo(filePath);
            m_fName_MTime[curFile] = fileInfo.lastModified();

            m_watcher.addPath(filePath);
        }
    }

    // 文件被删除
    for (const QString &prevFile : m_prevFiles)
    {
        if (!curFileSet.contains(prevFile))
        {
            // 文件被删除
            QString filePath = QDir(m_directory).filePath(prevFile);
            emit fileRemoved(filePath);
            qDebug() << "File removed:" << filePath;

            m_prevFiles.removeOne(prevFile);   // 更新现有文件列表
            m_fName_MTime.remove(prevFile);    // 更新map
            deleteTimer(prevFile);             // 删除相关定时器
            // m_watcher.removePath(filePath);    // 取消监视 [QFileSystemWatcher会自动解除]
        }
    }

//    // 更新已知文件集合和修改时间
//    m_prevFiles = curFileSet.values();
//    m_fName_MTime.clear();
//    for (const QString &file : m_prevFiles)
//    {
//        QFileInfo fileInfo(QDir(m_directory).filePath(file));
//        m_fName_MTime[file] = fileInfo.lastModified();
//    }
}

void DirectoryWatcher::onFileModify(const QString &path)
{
    // 检查是否修改
    QFileInfo fileInfo(path);
    QString fileName = QFileInfo(path).fileName();
    if(m_fName_MTime.contains(fileName) && fileInfo.lastModified() != m_fName_MTime[fileName])
    {
        qDebug() << "file modified: " << path;
        handleFileModification(fileName);
        m_fName_MTime[fileName] = fileInfo.lastModified(); // 更新最后修改时间
    }
}

void DirectoryWatcher::handleFileModification(const QString &fileName)
{
    // 文件内容被修改 启动或重置定时器
    // 对启动和重置的理解：当该文件第一次被修改 定时器启动
    // 当该文件被二次修改 if语句会将之前的定时器停止并创建新的定时器 即定时器被重置
    // 如此 只要3s内文件被二次修改 定时器重置 完美.

    if (m_timers.contains(fileName))
    {
        m_timers[fileName]->stop();
    }
    else
    {
        // 创建新的定时器
        m_timers[fileName] = new QTimer(this);
        // 场景：a文件0时刻被修改 2时刻被删除(文件删除连带定时器也删除) 到3时刻时 监视器认定他3s内未被修改
        // 此时触发a文件被修改的信号 此时会二次释放定时器 -- 访问空指针
        connect(m_timers[fileName], &QTimer::timeout, this, [this, fileName]()
        {
            if (m_timers.contains(fileName)) // 确保定时器仍然存在
            {
                QString filePath = QDir(m_directory).filePath(fileName);
                qDebug() << "File modified (after delay):" << filePath;
                emit fileModified(filePath);
                deleteTimer(fileName); // 释放定时器
            }

        });
    }

    // 启动定时器
    m_timers[fileName]->start(3000); // 3秒后触发
}

void DirectoryWatcher::deleteTimer(const QString &fileName)
{
    if (m_timers.contains(fileName))
    {
        delete m_timers[fileName];
        m_timers.remove(fileName);
    }
}


